package com.flying.server.network;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;

import com.flying.server.network.handler.IMsgHandler;
import com.flying.server.network.msg.ORMsg;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;


public class NetworkServer {

	private static final Object instanceLocker = new Object();
	private static NetworkServer instance = null;
	
	public static void init(String localIp,int localPort)
	{
		if (instance != null)
			return;
		
		synchronized(instanceLocker)
		{
			if (instance != null)
				return;
			
			instance = new NetworkServer(localIp,localPort);
			instance.startListen();
		}
	}
	
	public static NetworkServer getInstance()
	{
		synchronized(instanceLocker)
		{
			return instance;
		}
	}
	
	private String localIp;
	private int localPort;
	private Channel channel;
	
	private Object msgHandlerLocker = new Object();
	private Map<Short,IMsgHandler> msgHandler = new HashMap<Short,IMsgHandler>();
	
	public NetworkServer(String localIp,int localPort) {
		this.localIp = localIp;
		this.localPort = localPort;
		
	}
	/**
	 * 开始监听
	 */
	public void startListen() {
		
		if (channel != null && channel.isBound())
			return;
		
		ChannelFactory factory = new NioServerSocketChannelFactory(
				Executors.newCachedThreadPool(),
				Executors.newCachedThreadPool());
		
		ServerBootstrap bootstrap = new ServerBootstrap(factory);
		
		bootstrap.setPipelineFactory(new ChannelPipelineFactory(){

			@Override
			public ChannelPipeline getPipeline() throws Exception {
				
				ChannelPipeline pipeline =Channels.pipeline();
				pipeline.addLast("decoder", new MsgDecoder());
				pipeline.addLast("encoder", new MsgEncoder());
				pipeline.addLast("dispatcher", new MsgDispatchHandler());
				pipeline.addLast("event", new MsgEventHandler());
				return pipeline;
			}
		});
		
		bootstrap.setOption("child.tcpNoDelay", true); 
	    bootstrap.setOption("child.keepAlive", true);
	     
	    this.channel = bootstrap.bind(new InetSocketAddress(localIp,localPort));
	}
	/**
	 * 关闭网络
	 */
	public void close()
	{
		if (this.channel != null)
		{
			this.channel.disconnect();
			this.channel.unbind();
			this.channel.close();
		}
	}
	/**
	 * 注册消息处理
	 * @param type
	 * @param handler
	 */
	public void registerMsgHandler(short type,IMsgHandler handler)
	{
		synchronized(msgHandlerLocker)
		{
			if (!msgHandler.containsKey(type))
			{
				msgHandler.put(type, handler);
			}
		}
	}
	/**
	 * 接收到客户端消息
	 * @param msg
	 */
	public void onReceivedMsg(ORMsg msg)
	{
		System.out.println("onReceiveMsg msg.seq="+msg.getMsgSeq()+
				" msg.type="+msg.getMsgType()+" msg.len="+msg.getBodyBuffer().readableBytes());
		
		//TODO:这里需要把Dispatch动作扔到其他线程池来做，不做消息阻塞
		//当然，这个线程池的线程数量需要有最大限制。
		//目前先这样吧，因为netty是由多个workThread来处理消息的
		short type = msg.getMsgType();
		
		if (msgHandler.containsKey(type))
		{
			msgHandler.get(type).onMsg(msg);
		}
	}
}
